export default class DB {
    private dbName: string //数据库名称
    private db: any
    constructor(dbName: string) {
        this.dbName = dbName
    }

    //TODO:打开数据库
    public openStore(stores?: any) {
        console.log(stores);
        const request = window.indexedDB.open(this.dbName, 4)// 数据库名称，版本号
        //是的，如果指定的数据库不存在，window.indexedDB.open 方法会自动创建一个新的数据库。
        // 当调用 window.indexedDB.open 方法时，如果指定的数据库名称在浏览器中不存在，则会创建一个新的数据库，并且触发 onupgradeneeded 事件。你可以在 onupgradeneeded 事件的处理程序中定义数据库的结构和对象仓库。
        return new Promise((resolve, reject) => {
            request.onsuccess = (event: any) => {
                console.log("数据库打开成功！");
                this.db = event.target.result // 数据库对象
                console.log(this.db);
                resolve(true)
            }
            request.onerror = (e) => {
                console.log("数据库打开失败！");
                console.log(e);

            }
            // *数据库创建或升级的时候会触发
            request.onupgradeneeded = (event: any) => {
                console.log("数据库升级/创建成功!");
                // TODO:创建对象仓库
                const { result } = event.target
                for (const storeName in stores) { // 初始化多个objectStore对象仓库
                    const { keyPath, indexs } = stores[storeName]
                    if (!result.objectStoreNames.contains(storeName)) {
                        // 没有表则新建表
                        // keyPath：主键，主键key是默认建立索引的属性，autoIncrement是否自增
                        const store = result.createObjectStore(storeName, { autoIncrement: true, keyPath })
                        // todo:遍历的去创建索引
                        if (indexs && indexs.length > 0) { //如果有indexs就是改的操作，没有则是新增的操作
                            indexs?.map((indexName: string) => {
                                // store.createIndex(索引名称, 索引属性, 配置对象{ unique: true })
                                // 创建索引
                                // indexName索引列名称
                                // indexKey索引键值
                                store.createIndex(indexName, indexName, { unique: false })
                            })
                        }
                        // keyPath是主键键值，也可以不传然后设定autoIncrement：true自动创建键值
                        // 使用 createObjectStore 方法创建了一个新的对象存储空间（Object Store），并传入了它的名称以及可选的配置参数，比如 autoIncrement 选项和 keyPath。这些选项用来定义对象存储空间中的数据结构。
                        // 遍历了 indexs 数组，为每个索引名称创建了对应的索引。在调用 store.createIndex 方法时，你为每个索引指定了名称、索引属性，以及可选的配置对象，比如 unique 属性。
                        store.transaction.oncomplete = (event: any) => {
                            console.log("创建对象仓库成功");
                            //这段代码是用来监听 IndexedDB 事务成功完成的事件。当事务成功完成时，会触发 oncomplete 事件，然后执行所指定的回调函数
                        }
                    }
                }
            }
        })
    }

    // TODO:封装 增删改查 功能
    // 新增/修改数据库数据
    updateItem(storeName: string, data: any) {
        const transaction = this.db.transaction([storeName], 'readwrite')//通过 this.db.transaction 方法创建一个读写事务，并指定要访问的对象存储空间为 product 第二个参数表示是否只读
        const store = transaction.objectStore(storeName)//通过 transaction.objectStore 方法获取到了指定的对象存储空间
        const request = store.put({ ...data, updateTime: new Date().getTime() })
        // 使用store.put()方法将数据写入存储空间中。put()方法接受一个对象作为参数，这里将原始data对象的数据和一个名为updateTime的属性（表示更新时间）合并到一个新的对象中。
        console.log(6666);
        return new Promise((resolve, reject) => {
            request.onsuccess = (event: any) => {
                console.log("数据写入成功！");
                console.log(event);
                resolve(true)
            }
            request.onerror = (event: any) => {
                console.log("数据写入失败！");
                console.log(event);
            }
        })
    }

    // 删除数据
    deleteItem(storeName: string, key: number | string) {
        const transaction = this.db.transaction([storeName], 'readwrite')//通过 this.db.transaction 方法创建一个读写事务，并指定要访问的对象存储空间为 product 第二个参数表示是否只读
        const store = transaction.objectStore(storeName)//通过 transaction.objectStore 方法获取到了指定的对象存储空间
        const request = store.delete(key)
        // 使用store.put()方法将数据写入存储空间中。put()方法接受一个对象作为参数，这里将原始data对象的数据和一个名为updateTime的属性（表示更新时间）合并到一个新的对象中。
        request.onsuccess = (event: any) => {
            console.log("删除写入成功！");
            console.log(event);
        }
        request.onerror = (event: any) => {
            console.log("删除写入失败！");
            console.log(event);
        }
    }
    //TODO: 查询所有数据
    getAllList(storeName: string) {
        const transaction = this.db.transaction(storeName)//通过 this.db.transaction 方法创建一个读写事务，并指定要访问的对象存储空间为 product 第二个参数表示是否只读
        const store = transaction.objectStore(storeName)//通过 transaction.objectStore 方法获取到了指定的对象存储空间
        const request = store.getAll()
        return new Promise((resolve, reject) => {
            request.onsuccess = (event: any) => {
                console.log("查询所有数据成功！");
                console.log(event.target.result);
                resolve(event.target.result)
            }
            request.onerror = (event: any) => {
                console.log("查询所有数据失败！");
                console.log(event);
            }
        })
        // 使用store.put()方法将数据写入存储空间中。put()方法接受一个对象作为参数，这里将原始data对象的数据和一个名为updateTime的属性（表示更新时间）合并到一个新的对象中。

    }
    // TODO:查询某一条数据
    async getItem(storeName: string, key: number | string) {

        await this.openStore()

        const transaction = this.db.transaction(storeName)//通过 this.db.transaction 方法创建一个读写事务，并指定要访问的对象存储空间为 product 第二个参数表示是否只读
        const store = transaction.objectStore(storeName)//通过 transaction.objectStore 方法获取到了指定的对象存储空间
        const request = store.get(key)
        // 使用store.put()方法将数据写入存储空间中。put()方法接受一个对象作为参数，这里将原始data对象的数据和一个名为updateTime的属性（表示更新时间）合并到一个新的对象中。
        return new Promise((resolve, reject) => {
            request.onsuccess = (event: any) => {
                console.log("查询某一条数据成功！");
                console.log(event.target.result);
                resolve(event.target.result)
            }
            request.onerror = (event: any) => {
                console.log("查询某一条数据失败！");
                console.log(event);
                reject(event)
            }
        })

    }

}
